package com.photonpay.api.client;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson2.JSON;
import com.photonpay.api.config.PhotonPayConfig;
import com.photonpay.api.config.PhotonPayConfigHolder;
import com.photonpay.api.request.AccessTokenRequest;
import com.photonpay.api.request.BaseRequest;
import com.photonpay.api.response.AccessTokenResponse;
import com.photonpay.api.response.BaseResponse;
import com.photonpay.api.service.PhotonPayService;
import com.photonpay.api.service.impl.PhotonPayServiceImpl;
import com.photonpay.api.util.RSAUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @author ：lo-
 * @date ：Created in 2023/11/22 14:15
 */
@Slf4j
public class DefaultPhotonPayClient implements PhotonPayApiClient {

    public DefaultPhotonPayClient() {
    }

    /**
     * 授权token前缀
     */
    public static final String AUTH_TOKEN_PREFIX = "basic ";

    /**
     * token key
     */
    public static final String AUTH_TOKEN_KEY = "X-PD-TOKEN";

    /**
     * 签名key
     */
    public static final String SING_KEY = "X-PD-SIGN";

    // 本地配置记录
    private final Map<String, PhotonPayConfig> configMap = new HashMap<>();

    private final PhotonPayService photonPayService = new PhotonPayServiceImpl(this);

    @Override
    public PhotonPayService getPhotonPayService() {
        return this.photonPayService;
    }

    /**
     * 发起请求
     * @param request 请求参数
     * @return 响应信息
     */
    @Override
    public <T extends BaseResponse> T execute(BaseRequest<T> request) {
        PhotonPayConfig config = this.getPhotonPayConfig();
        HttpRequest httpRequest = HttpUtil.createRequest(request.getMethod(), config.getServerUrl() + request.getBasePath());
        if (request.isGetTokenPath()) {
            // 拼接 appId/appSecret 再 base64后 得到 token
            httpRequest.auth(AUTH_TOKEN_PREFIX + Base64.encode(config.getAppId().concat("/").concat(config.getAppSecret())));
        }
        // 配置token
        if (request.isAccessToken()) {
            httpRequest.header(AUTH_TOKEN_KEY, getAccessToken());
        }
        String jsonString = JSON.toJSONString(request);
        if (httpRequest.getMethod().equals(Method.GET)) {
            // BeanUtil.beanToMap(request)会导致 @JSONField 的字段不生效，这里使用JSONObject
            httpRequest.form(JSON.parseObject(jsonString));
        } else {
            httpRequest.body(jsonString);
        }
        if (request.isSign()) {
            String sign = RSAUtil.sign(new String(httpRequest.bodyBytes()), config.getPrivateKey());
            httpRequest.header(SING_KEY, sign);
        }
        log.info("\n请求方式:{}\n请求url:{}\n请求头:{}\n请求body:{}", httpRequest.getMethod().name(), httpRequest.getUrl(), httpRequest.headers(), jsonString);
        try {
            HttpResponse execute = httpRequest.execute();
            String body = execute.body();
            log.info("\n响应头信息{}\n响应数据:{}", execute.headers(), body);
            BaseResponse response = JSON.parseObject(body, BaseResponse.class);
            if (response.isSuccess()) {
                return JSON.parseObject(body, request.getResponseClass());
            }
            // 失败只返回错误信息
            return BeanUtil.copyProperties(response, request.getResponseClass());
        } catch (Exception e) {
            T t = ReflectUtil.newInstance(request.getResponseClass());
            t.setCode("-1");
            t.setMsg(e.getMessage());
            return t;
        }
    }

    /**
     * 切换配置
     *
     * @param appKey appKey
     * @return true = 切换成功
     */
    public boolean switchover(String appKey) {
        if (this.configMap.containsKey(appKey)) {
            PhotonPayConfigHolder.set(appKey);
            return true;
        }
        return false;
    }

    /**
     * 添加配置
     * @param appId appId
     * @param configStorage 配置信息
     */
    public void addConfig(String appId, PhotonPayConfig configStorage) {
        synchronized (this) {
            PhotonPayConfigHolder.set(appId);
            this.configMap.put(appId, configStorage);
        }
    }

    /**
     * 获取token
     *
     * @return token
     */
    public String getAccessToken() {
        PhotonPayConfig config = this.getPhotonPayConfig();
        if (!config.isAccessTokenExpired()) {
            return config.getAccessToken();
        }
        AccessTokenResponse rsp = execute(AccessTokenRequest.builder().build());
        if (rsp.isSuccess()) {
            config.updateAccessToken(rsp);
            return config.getAccessToken();
        }
        throw new RuntimeException(rsp.getMsg());
    }

    /**
     * 获取配置
     * @return 配置
     */
    public PhotonPayConfig getPhotonPayConfig() {
        if (this.configMap.size() == 1) {
            // 只有一个配置，直接返回其配置即可
            return this.configMap.values().iterator().next();
        }
        return this.configMap.get(PhotonPayConfigHolder.get());
    }

}
